/**
 *******************************************************************************
 * @file flash_driver.c
 * @author .ISS_AUTO (hudandan@issauto.com)
 * @version V0.0.0  2024-03-22
 *                  移植MCU-N32G45x,实现以下接口：
 *                  1. int32_t iss_flash_erase(uint32_t start_addr, uint32_t len);
 *                  2. int32_t iss_flash_write(uint32_t write_addr, void *data, uint32_t len);
 *                  3. int32_t iss_flash_read(uint32_t read_addr, void *data, uint32_t len);
 *
 * @brief This file for for flash interface.
 *
 * @copyright Copyright (c) 2024 ISSAUTO TECH Co., Ltd. All rights reserved.
 *
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "flash_driver.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* PRQA S 2740, 2870, 3383 ++ */

/**
 * @brief Erase Data by erase page operation
 *
 * @param start_addr
 * @param len
 */
int32_t iss_flash_erase(uint32_t start_addr, uint32_t len)
{
    int32_t errCode = 0U;
    uint32_t end_addr = start_addr + len;

    ISS_ASSERT((start_addr >= ISS_FLASH_BASE_ADDR) && (start_addr < ISS_FLASH_END_ADDR));
    ISS_ASSERT((len > 0) && (end_addr < ISS_FLASH_END_ADDR));

    int32_t errFlash = 0U;

    /* Unlocks the FLASH Program Erase Controller */
    FLASH_Unlock();

    for (size_t i = start_addr; i < end_addr; i += ISS_PAGE_SIZE) {
        /* Erase the flash pages */
        errFlash = FLASH_EraseOnePage(i);
        ISS_ASSERT(errFlash == FLASH_COMPL);

        if (FLASH_COMPL != errFlash) {
            errCode = -1U;
            goto eraseExit;
        }
    }

eraseExit:
    /* Locks the FLASH Program Erase Controller */
    FLASH_Lock();

    return errCode;
}

/**
 * @brief Write data to the flash memory by program Word operation.
 *
 * @param write_addr
 * @param data
 * @param len
 */
int32_t iss_flash_write(uint32_t write_addr, void *data, uint32_t len)
{
    int32_t errCode = 0U;
    uint32_t *write_buf = (uint32_t *)data;
    uint32_t write_len = len / sizeof(uint32_t);

    ISS_ASSERT((write_addr >= ISS_FLASH_BASE_ADDR) && (write_addr < ISS_FLASH_END_ADDR));
    ISS_ASSERT((data != NULL) && (len > 0));

    int32_t errFlash = 0U;

    /* Unlocks the FLASH Program Erase Controller */
    FLASH_Unlock();

    /* program flash */
    for (size_t i = 0; i < write_len; i++) {
        errFlash = FLASH_ProgramWord(write_addr, *write_buf);
        ISS_ASSERT(errFlash == FLASH_COMPL);

        if (FLASH_COMPL != errFlash) {
            errCode = -1U;
            goto writeExit;
        }

        write_buf ++;    //!< Has wrote one word to the flash memory.
        write_addr += 4; //!< Offset one word -> 1*Word = 4*Byte.
    }

writeExit:
    /* Locks the FLASH Program Erase Controller */
    FLASH_Lock();

    return errCode;
}

/**
 * @brief Read data from the flash memory.
 *
 * @param read_addr
 * @param data
 * @param len
 */
int32_t iss_flash_read(uint32_t read_addr, void *data, uint32_t len)
{
    int32_t errCode = 0U;
    uint32_t *read_buf = (uint32_t *)data;
    uint32_t read_len = len / sizeof(uint32_t);

    ISS_ASSERT((read_addr >= ISS_FLASH_BASE_ADDR) && (read_addr < ISS_FLASH_END_ADDR));
    ISS_ASSERT((data != NULL) && (len > 0));

    for (size_t i = 0; i < read_len; i++) {
        *read_buf = *(__IO uint32_t *) read_addr;

        read_buf ++; //!< Has read one word from the flash memory.
        read_addr += 4; //!< Offset one word -> 1*Word = 4*Byte.
    }

    return errCode;
}

/* PRQA S 2740, 2870, 3383 -- */

/* END OF FILE ---------------------------------------------------------------*/
